# coding=utf-8
"""
author: jamon
"""
import enum
import random

from obespoir.share.singleton import Singleton

from package.universe import universe, GateItem
from package.act_record import ActRecord
from typing import List, Dict, Optional


class GateStatus(enum.Enum):

    PREPARING = 1  # 准备中
    RUNNING = 2  # 运行中
    FINISHING = 3  # 结束中
    FINISHED = 4  # 已结束


class GateData(object, metaclass=Singleton):

    def __init__(self):
        self.gate_id: int = 1  # 第几关
        self.config: Optional[GateItem] = None

        # 当前是第几波npc
        self.cur_npc_wave_no: int = 0
        # 最近一次npc产生的帧时间
        self.last_npc_frame_no: int = 0

        # 当前帧数
        self.cur_logic_frame_no: int = 0  # 逻辑帧
        self.cur_physical_frame_no: int = 0  # 物理帧
        self.target_frame_no: int = 0  # 目标帧

        # 帧率
        self.frame_sync_rate = 12
        self.frame_physical_rate = 60

        # 随机数种子
        self.random_seed: int = 15928409239

        # 已经执行过的操作记录
        self.act_records: List[ActRecord] = []

        # 缓存的待执行的逻辑帧操作
        self.cache_to_act: Dict[int, List[ActRecord]] = {}

        # 是否联网模式
        self.is_net_mode: bool = False

        # 格子大小
        self.GRID_SIZE = 24

        self.status: GateStatus = GateStatus.RUNNING

    def __str__(self):
        return "<{} gate_id={} cur_npc_wave_no={} last_npc_frame_no={} " \
               "cur_logic_frame_no={}>"\
            .format(
                self.__class__.__name__, self.gate_id, self.cur_npc_wave_no,
                self.last_npc_frame_no, self.cur_logic_frame_no
            )

    __repr__ = __str__

    def init_gate(self, gate_id: int):
        self.gate_id: int = gate_id  # 第几关
        self.config: GateItem = universe.get_gate_info(self.gate_id)

    def reset(self):
        # 当前是第几波npc
        self.cur_npc_wave_no: int = 0
        # 最近一次npc产生的帧时间
        self.last_npc_frame_no: int = 0

        # 当前帧数
        self.cur_logic_frame_no: int = 0  # 逻辑帧
        self.cur_physical_frame_no: int = 0  # 物理帧
        self.target_frame_no = 0  # 目标帧

        # 帧率
        self.frame_sync_rate = 12
        self.frame_physical_rate = 60

        # 随机数种子
        self.random_seed: int = 15928409239

        # 已经执行过的操作记录
        self.act_records: List[ActRecord] = []

        # 缓存的待执行的逻辑帧操作
        self.cache_to_act: Dict[int, List[ActRecord]] = {}

        self.status = GateStatus.RUNNING

    @property
    def frame_ratio(self):
        return int(self.frame_physical_rate / self.frame_sync_rate)

    def has_can_do_action(self) -> List[ActRecord]:
        """是否有可执行的操作"""
        if self.cache_to_act:
            if self.cur_logic_frame_no in self.cache_to_act:
                return self.cache_to_act[self.cur_logic_frame_no]
        return []

    def init_random_seed(self, seed: int):
        self.random_seed = seed
        random.seed(seed)

    def update_frame_no(self) -> bool:
        """
        :return: bool, 是否可以进入下一个逻辑帧
        """
        self.cur_physical_frame_no += 1
        self.cur_logic_frame_no += 1
        return True
        # if self.cur_physical_frame_no == (
        #         self.cur_logic_frame_no + 1) * self.frame_ratio:
        #     # 可以进入下一个逻辑帧
        #     self.cur_logic_frame_no += 1
        #     return True
        # return False

    def add_to_act(self, act: ActRecord):
        next_frame = self.cur_logic_frame_no + 1
        act.set_frame_no(next_frame)
        if next_frame not in self.cache_to_act:
            self.cache_to_act[next_frame] = []
        else:
            # 同一个逻辑帧内同样的操作以最后1次为准
            for i in range(len(self.cache_to_act[next_frame]) - 1, -1, -1):
                _act = self.cache_to_act[next_frame][i]
                if _act.act_type == act.act_type and \
                        _act.extra_params == act.extra_params:
                    self.cache_to_act[next_frame].pop(i)
        self.cache_to_act[next_frame].append(act)

    def add_to_acts(self, acts: Dict[int, List[dict]]):
        """
        添加指定帧待执行的操作
        :param acts:
        :return:
        """
        for fn, r in acts.items():
            fn = int(fn)
            if fn not in self.cache_to_act:
                self.cache_to_act[fn] = []
            act_list = [ActRecord.from_dict(act) for act in r]
            self.cache_to_act[fn].extend(act_list)

    def get_cur_act_records(self) -> List[ActRecord]:
        """获取当前逻辑帧的操作"""
        if self.cur_logic_frame_no in self.cache_to_act:
            return self.cache_to_act[self.cur_logic_frame_no]
        return []

    def clear_acts(self, frame_no: int):
        """清除指定帧的操作"""
        if frame_no in self.cache_to_act:
            self.cache_to_act.pop(frame_no)
